package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.ArticleConfigMapper;
import com.heima.article.mapper.ArticleContentMapper;
import com.heima.article.mapper.ArticleMapper;
import com.heima.article.service.ArticleService;
import com.heima.common.redis.RedisCacheService;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.dtos.ArticleHomeDto;
import com.heima.model.article.dtos.HotArticleVo;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.article.pojos.ApArticleContent;
import com.heima.model.common.constants.ArticleConstants;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.search.dtos.SearchArticleVo;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.*;

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, ApArticle> implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private ArticleContentMapper articleContentMapper;

    @Autowired
    private ArticleConfigMapper articleConfigMapper;

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;

    @Autowired
    private RedisCacheService redisCacheService;

    /**
     * 加载首页-加载更多-加载更新 三位一体
     *
     * @param dto  type=1 认为是加载更多，type=2表示加载更新
     * @param type
     * @return
     */
    @Override
    public ResponseResult load(ArticleHomeDto dto, Short type) {
        //1.非空判断
        if(dto.getSize()==0){
            dto.setSize(10);
        }
        if(dto.getTag()==null){
            dto.setTag(ArticleConstants.DEFAULT_TAG);
        }
        if(dto.getMinBehotTime()==null){
            dto.setMinBehotTime(new Date());
        }
        if(dto.getMaxBehotTime()==null){
            dto.setMaxBehotTime(new Date());
        }

        //2. 直接调用sql,执行查询(判断类型，排序)
        List<ApArticle> apArticles = articleMapper.loadArticleList(dto, type);

        //3.返回数据
        return ResponseResult.okResult(apArticles);
    }

    /**
     * 优化查询首页，根据redis去查询数据
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult load2(ArticleHomeDto dto) {
        //获取redis的key前缀
        String prefixKey = ArticleConstants.HOT_ARTICLE_FIRST_PAGE;
        String hotArticleVoListStr = redisCacheService.get(prefixKey + dto.getTag());
        //转成对象
        List<HotArticleVo> hotArticleVos = JSONArray.parseArray(hotArticleVoListStr, HotArticleVo.class);
        return ResponseResult.okResult(hotArticleVos);
    }

    /**
     * 保存三剑客
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional
    public ResponseResult save(ArticleDto dto) {
        ApArticle apArticle=new ApArticle();
        BeanUtils.copyProperties(dto,apArticle);

        ApArticleContent apArticleContent=null;
        //1.如果是新增
        if(dto.getId()==null){
            //新增ap_article
            super.save(apArticle);

            //新增ap_article_config
            ApArticleConfig apArticleConfig=new ApArticleConfig(apArticle.getId());
            articleConfigMapper.insert(apArticleConfig);

            //新增ap_article_content
            apArticleContent=new ApArticleContent();
            apArticleContent.setArticleId(apArticle.getId());
            apArticleContent.setContent(dto.getContent());
            articleContentMapper.insert(apArticleContent);

        }else{
            //2.如果是修改
            //修改ap_article
            super.updateById(apArticle);
            //修改ap_article_content
           apArticleContent = articleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, dto.getId()));
            if(apArticleContent!=null){
                apArticleContent.setContent(dto.getContent());
                articleContentMapper.updateById(apArticleContent);
            }
        }
        //2.5 生成静态化文件
        this.generHtmlToMinio(apArticle.getId());

        //3.返回数据,要不要返回文章id ，因为wmnews表中需要
        return ResponseResult.okResult(apArticle.getId());
    }


    @Autowired
    private Configuration configuration;

    @Autowired
    private FileStorageService fileStorageService;

    @Async
    public void generHtmlToMinio(Long id){
        //1.根据文章id获取文章内容数据
        ApArticleContent apArticleContent = articleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, id));
        if(apArticleContent==null){
            return;
        }
        //2.生成静态化文件
        Template template = null;
        try {
            template = configuration.getTemplate("article.ftl");
            Map dataModel=new HashMap();
            String content = apArticleContent.getContent();
            dataModel.put("content", JSONArray.parseArray(content));
            //声明字符串写入流对象，此时当前这个对象中是没有任何数据
            StringWriter out=new StringWriter();
            template.process(dataModel,out);//如果走完当前这行代码，此时写入流对象中就有了数据
            //3.上传到minio中
            InputStream inputStream=new ByteArrayInputStream(out.toString().getBytes());
            String path = fileStorageService.uploadHtmlFile("", apArticleContent.getArticleId() + ".html", inputStream);

            //4.修改ap_article表中static_url字段的值
            ApArticle entity=articleMapper.selectById(apArticleContent.getArticleId());
            entity.setStaticUrl(path);
            articleMapper.updateById(entity);

            //发送消息内容
            sendMessage(apArticleContent,entity);


            inputStream.close();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //发送消息
    private void sendMessage(ApArticleContent apArticleContent, ApArticle entity) {
        //发送消息内容给kafka
        SearchArticleVo vo=new SearchArticleVo();
        BeanUtils.copyProperties(entity,vo);
        //布局
        vo.setLayout(entity.getLayout().intValue());
        //内容
        vo.setContent(apArticleContent.getContent());
        //suggestion
        List<String> suggestion = fengzhuangSuggestion(vo);
        vo.setSuggestion(suggestion);

        String data= JSON.toJSONString(vo);
        kafkaTemplate.send(ArticleConstants.ARTICLE_ES_SYNC_TOPIC,data);
    }

    /**
     * 解决封装suggestion的方法
     * @param articleVo
     */
    private List<String > fengzhuangSuggestion(SearchArticleVo articleVo) {

        //1.实例化list
        List<String > suggesion=new ArrayList<>();

        //2.解析content
        String content = articleVo.getContent();
        List<Map> contentList = JSONArray.parseArray(content, Map.class);
        for (Map map : contentList) {
            if(map.get("type").equals("text")){
                String value = (String) map.get("value");
                String[] split = value.split(",");
                suggesion.addAll(Arrays.asList(split));
            }
        }
        //添加标题
        suggesion.add(articleVo.getTitle());

        return suggesion;
    }
}
